﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace hmi
{
    public delegate void FeedbackHandler(string inf);
    //public delegate void BasicFeedbackHandler(string dataState, string selfCheckState, string view, string outMode, string workMode, string targetInf);

    class Protocol
    {
        //public event BasicFeedbackHandler InfFeedbackEvent;
        public event FeedbackHandler DataStateFdbackEvent;
        public event FeedbackHandler SelfCheckStateFdbackEvent;
        //public event FeedbackHandler GainFdbackEvent;
        public event FeedbackHandler ViewFdbackEvent;
        //public event FeedbackHandler FocusFdbackEvent;
        //public event FeedbackHandler ContrastFdbackEvent;
        public event FeedbackHandler OutModeFdbackEvent;
        public event FeedbackHandler WorkModeFdbackEvent;
        //public event FeedbackHandler VideoRecordSateFdbackEvent;
        //public event FeedbackHandler CrossModeFdbackEvent;
        public event FeedbackHandler TargetInfFdbackEvent;

        private const int GAIN_MAX = 100;
        private const int GAIN_MIN = 0;
        private const int FOCUS_MAX = 150;
        private const int FOCUS_MIN = 50;
        private const int CONTRAST_MAX = 100;
        private const int CONTRAST_MIN = 0;

        private const int TARGET_NUM_INDEX = 7;

        private const byte HEAD1 = 0xE0;//上位机发送、接收数据的帧头1
        private const byte HEAD2_EVENT = 0x00;//事件触发时 上位机发送、接收数据的帧头2          
        private const byte HEAD2_CYCLE = 0x01;//周期发送时 上位机收到数据的帧头2

        private const byte END = 0xFB;//数据帧尾为0xFB

        private const int FRAME_MIN_LEN = 6;//至少包含数据帧头(2字节)、数据内容（至少2字节）、校验和(1字节)、帧尾（1字节）
        private const int FRAME_CYCLE_LEN = 50;//一帧数据50个字节

        private const int BUFFER_SIZE = 1024;
        private Queue<byte> buffer = new Queue<byte>(BUFFER_SIZE);//最多一次读取到的数据

        private byte header1Send;//帧头1
        private byte header2Send;//帧头2
        private byte funcCodeSend;
        private byte commandSend;
        private byte dataSend;
        private byte end;//帧尾
        private byte[] _frameSend = new byte[7];

        public byte[] FrameSend//被发送的数据帧
        {
            get
            {
                _frameSend[0] = header1Send;
                _frameSend[1] = header2Send;
                _frameSend[2] = funcCodeSend;
                _frameSend[3] = commandSend;
                _frameSend[4] = dataSend;
                byte checksum = 0;
                for (int i = 2; i <= 4; i++)
                {
                    checksum += _frameSend[i];
                }
                _frameSend[5] = checksum;
                _frameSend[6] = end;
                return _frameSend;
            }
        }

        //private byte targetNum;//检测到的目标数量
        private static readonly Protocol _instance = null;

        static Protocol()
        {
            _instance = new Protocol();
        }

        private Protocol()
        {
            DefaultSendEvent();
        }

        public static Protocol Instance
        {
            get
            {
                return _instance;
            }
        }

        private void DefaultSendEvent()
        {
            header1Send = HEAD1;
            header2Send = HEAD2_EVENT;
            dataSend = 0x00;
            end = END;
        }

        public void ExtractData(byte[] inputBytes)
        {
            foreach (var value in inputBytes)
            {
                buffer.Enqueue(value);
            } 
            while (buffer.Count >= FRAME_MIN_LEN)
            {
                if (buffer.ElementAt(0) != HEAD1)
                {
                    //如果数据开始不是头，则删除数据   
                    buffer.Dequeue();
                    continue;
                }
                if (buffer.ElementAt(1) == HEAD2_CYCLE)
                {
                    if (buffer.Count < FRAME_CYCLE_LEN)
                    {
                        break; //数据太少 什么都不做 等待接收更多的数据
                    }
                    
                    //int frameLen = 4 * targetNum + TARGET_NUM_INDEX + 3;
                    //if (buffer.Count < frameLen)
                    //{
                    //    break; //数据量不到一帧 未收到表示目标数目的字节 什么都不做 等待接收更多的数据
                    //}
                    if (buffer.ElementAt(FRAME_CYCLE_LEN - 1) != END)//判断帧尾
                    {
                        for (int i =1;i<=2;i++)//删除头上两个数据
                        {
                            buffer.Dequeue();
                        }
                        continue;
                    }
                    //继续判断校验位
                    byte checksum = 0;
                    for (int i = 2; i <= FRAME_CYCLE_LEN - 3; i++)
                    {
                        checksum += buffer.ElementAt(i);
                    }
                    if (checksum != buffer.ElementAt(FRAME_CYCLE_LEN - 2))
                    {
                        for (int i = 1; i <= 2; i++)//删除头上两个数据
                        {
                            buffer.Dequeue();
                        }
                        continue;
                    }
                    //至此，已经被找到了一条完整数据，然后分析数据 
                    byte[] frame = new byte[FRAME_CYCLE_LEN];
                    for (int i = 0; i < FRAME_CYCLE_LEN; i++)//删除头上两个数据
                    {
                        frame[i] = buffer.Dequeue();
                    }
                    CycleReceiveFrameParse(frame);
                }
                else
                {
                    buffer.Dequeue();//从缓存中删除错误数据  
                    continue;
                }
            }
        }                 

        private void CycleReceiveFrameParse(byte[] frame)//周期发送的数据帧解析
        {
            string dataStateFb;
            switch (frame[2])
            {
                case 0x00:
                    dataStateFb = "正常";
                    break;
                case 0x01:
                    dataStateFb = "异常";
                    break;
                default:
                    dataStateFb = "非法数据";
                    break;
            }
            string selfCheckStateFb;
            switch (frame[3])
            {
                case 0x00:
                    selfCheckStateFb = "正常";
                    break;
                case 0x01:
                    selfCheckStateFb = "异常";
                    break;
                default:
                    selfCheckStateFb = "非法数据";
                    break;
            }
            //string gainFb = frame[4]+"%";
            //string focusFb = frame[5] + "mm";
            //string contrastFb = frame[6].ToString();
            string outModeFb;
            switch (frame[4])
            {
                case 0x01:
                    outModeFb = "原图输出";
                    break;
                case 0x02:
                    outModeFb = "增强输出";
                    break;
                case 0x03:
                    outModeFb = "信息叠加";
                    break;
                default:
                    outModeFb = "非法数据";
                    break;
            }
            string workModeFb;
            switch (frame[5])
            {
                case 0x01:
                    workModeFb = "工作模式"; 
                    break;
                case 0x02:
                    workModeFb = "待机模式";
                    break;
                default:
                    workModeFb = "非法数据";
                    break;
            }
            string viewFb = frame[6]/10.0 + "°";
            byte targetNum = frame[TARGET_NUM_INDEX];
            string targetInf = string.Format("目标数量：{0:G}\n", targetNum);
            for (int i = 0; i < targetNum; i++)
            {
                double u = (frame[TARGET_NUM_INDEX+1 + 4 * i] + frame[TARGET_NUM_INDEX + 1 + 4 * i + 1] * 256) / 10.0;
                double v = (frame[TARGET_NUM_INDEX + 1 + 4 * i + 2] + frame[TARGET_NUM_INDEX + 1 + 4 * i + 3] * 256) / 10.0;
                targetInf += string.Format("目标:{0:G} u:{1:G} v:{2:G}\n", i+1,u,v);                
            }
            DataStateFdbackEvent?.Invoke(dataStateFb);
            SelfCheckStateFdbackEvent?.Invoke(selfCheckStateFb);
            //GainFdbackEvent?.Invoke(gainFb);
            ViewFdbackEvent?.Invoke(viewFb);
            //FocusFdbackEvent?.Invoke(focusFb);
            //ContrastFdbackEvent?.Invoke(contrastFb);
            OutModeFdbackEvent?.Invoke(outModeFb);
            WorkModeFdbackEvent?.Invoke(workModeFb);
            //VideoRecordSateFdbackEvent?.Invoke(videoRecordSateFb);
            //CrossModeFdbackEvent?.Invoke(crossModeFb);
            TargetInfFdbackEvent?.Invoke(targetInf);
            //InfFeedbackEvent?.Invoke(dataStateFb, selfCheckStateFb, viewFb, outModeFb, workModeFb, targetInf);  
        }

        private void SendFrame()//发送数据帧
        {
            CommManage.Instance.SendByteData(FrameSend);
        }

        private void SelfCheckCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC0;            
        }

        public void SelfCheckStart()//开始自检
        {
            SelfCheckCode();
            commandSend = 0x00;
            SendFrame();
        }

        private void GainCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC1;
        }

        public void GainAdd()//增加增益
        {
            GainCode();
            commandSend = 0x01;
            SendFrame();
        }

        public void GainDec()//减小增益
        {
            GainCode();
            commandSend = 0x02;
            SendFrame();
        }        

        public void GainSet(double value)//绝对值式增益设置
        {
            GainCode();
            commandSend = 0x03;
            double gain;
            if (value >= GAIN_MAX)
            {
                gain = GAIN_MAX;
            }
            else if (value <= GAIN_MIN)
            {
                gain = GAIN_MIN;
            }
            else
            {
                gain = value;
            }
            byte gainToByte = Convert.ToByte(value - GAIN_MIN);
            dataSend = gainToByte;
            SendFrame();
        }

        public void GainAuto()//增益自动
        {
            GainCode();
            commandSend = 0x04;
            SendFrame();
        }

        private void FocusCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC2;
        }

        public void ViewFieldAdd()//视场角增加
        {
            FocusCode();
            commandSend = 0x01;
            SendFrame();
        }

        public void ViewFieldDec()//视场角减小
        {
            FocusCode();
            commandSend = 0x02;
            SendFrame();
        }
        public void FocusSet(double value)//绝对值式焦距设置
        {
            FocusCode();
            commandSend = 0x03;
            double focus;
            if (value >= FOCUS_MAX)
            {
                focus = FOCUS_MAX;
            }
            else if (value <= FOCUS_MIN)
            {
                focus = FOCUS_MIN;
            }
            else
            {
                focus = value;
            }
            byte focusToByte = Convert.ToByte(value);
            dataSend = focusToByte;
            SendFrame();
        }

        public void FocusAuto()//焦距自动
        {
            FocusCode();
            commandSend = 0x04;
            SendFrame();
        } 

        private void ContrastCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC3;
        }

        public void ContrastAdd()//对比度增加
        {
            ContrastCode();
            commandSend = 0x01;
            SendFrame();
        }

        public void ContrastDec()//对比度减小
        {
            ContrastCode();
            commandSend = 0x02;
            SendFrame();
        }

        public void ContrastSet(double value)//绝对值式对比度设置
        {
            ContrastCode();
            commandSend = 0x03;
            double contrast;
            if (value >= CONTRAST_MAX)
            {
                contrast = CONTRAST_MAX;
            }
            else if (value <= CONTRAST_MIN)
            {
                contrast = CONTRAST_MIN;
            }
            else
            {
                contrast = value;
            }
            byte contrastToByte = Convert.ToByte(value - CONTRAST_MIN);
            dataSend = contrastToByte;
            SendFrame();
        }

        public void ContrastAuto()//对比度自动
        {
            ContrastCode();
            commandSend = 0x04;
            SendFrame();
        }

        private void OutModeCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC4;
        }

        public void OriginalImage()//原图模式
        {
            OutModeCode();
            commandSend = 0x01;
            SendFrame();
        }

        public void Enhance()//增强输出
        {
            OutModeCode();
            commandSend = 0x02;
            SendFrame();
        }

        public void Superposition()//信息叠加
        {
            OutModeCode();
            commandSend = 0x03;
            SendFrame();
        }

        private void WorkModeCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC5;
        }

        public void WorkMode()//工作模式
        {
            WorkModeCode();
            commandSend = 0x01;
            SendFrame();
        }

        public void StandbyMode()//待机模式
        {
            WorkModeCode();
            commandSend = 0x02;
            SendFrame();
        }

        private void RecordCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC6;
        }

        public void StartRecord()//开始录制
        {
            RecordCode();
            commandSend = 0x01;
            SendFrame();
        }

        public void StopRecord()//结束录制
        {
            RecordCode();
            commandSend = 0x02;
            SendFrame();
        }        

        private void CrossCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC4;
        }

        public void CrossLoad()//加载十字线
        {
            CrossCode();
            commandSend = 0x21;
            SendFrame();
        }

        public void CrossBlank()//消隐十字线
        {
            CrossCode();
            commandSend = 0x20;
            SendFrame();
        }

        private void VersionCode()
        {
            DefaultSendEvent();
            funcCodeSend = 0xC8;
        }
    }
}
